#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>

#define PORT 4321
#define MAX_FILENAME 256

int recv_all(int sock, void *buf, int len) {
    int received = 0;
    while (received < len) {
        int n = recv(sock, (char*)buf + received, len - received, 0);
        if (n <= 0) return n;
        received += n;
    }
    return received;
}

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addrlen = sizeof(client_addr);
    char buf[4096];

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    listen(server_fd, 1);
    printf("等待连接在端口%d...\n", PORT);

    while (1) {
        client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addrlen);
        printf("连接来自: %s\n", inet_ntoa(client_addr.sin_addr));
        while (1) {
           // 1. 接收4字节（文件名长度或心跳包）
            unsigned char header[4];
            int n = recv_all(client_fd, header, 4);
            if (n != 4) {
                printf("客户端断开连接或收到无效头，关闭连接\n");
                break;
            }
            // 检查心跳包
            if (memcmp(header, "PING", 4) == 0) {
                send(client_fd, "PONG", 4, 0);
                printf("收到心跳包，已回复PONG\n");
                continue;
            }
            // 文件名长度
            int filename_size = (unsigned int)header[0] | ((unsigned int)header[1]<<8) | ((unsigned int)header[2]<<16) | ((unsigned int)header[3]<<24);
            printf("接收文件名大小: %d字节\n", filename_size);
            if (filename_size <= 0 || filename_size > 255) {
                printf("Invalid filename size: %d\n", filename_size);
                break;
            }
            // 文件名
            char filename[MAX_FILENAME] = {0};
            n = recv_all(client_fd, filename, filename_size);
            if (n != filename_size) {
                printf("文件名接收失败\n");
                break;
            }
            filename[filename_size] = '\0';
            if (filename_size < 4 || strcmp(filename + filename_size - 4, ".jpg") != 0) {
                printf("Invalid file extension\n");
                break;
            }
            // 生成以时间为名的文件名
            struct timeval tv;
            gettimeofday(&tv, NULL);
            struct tm *tm_info = localtime(&tv.tv_sec);
            char time_filename[512];
            // 创建 photos 文件夹（如果不存在）
            struct stat st = {0};
            if (stat("photos", &st) == -1) {
                mkdir("photos", 0755);
            }
            snprintf(time_filename, sizeof(time_filename), "photos/%04d%02d%02d_%02d%02d%02d_%03ld.jpg",
                tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
                tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, tv.tv_usec / 1000);
            printf("保存文件名: %s\n", time_filename);
            // 文件大小
            unsigned char size_buf[4];
            n = recv_all(client_fd, size_buf, 4);
            if (n != 4) {
                printf("Invalid file size header\n");
                break;
            }
            int file_size = (unsigned int)size_buf[0] | ((unsigned int)size_buf[1]<<8) | ((unsigned int)size_buf[2]<<16) | ((unsigned int)size_buf[3]<<24);
            printf("接收文件大小: %d字节\n", file_size);
            if (file_size <= 0) {
                printf("Invalid file size: %d\n", file_size);
                break;
            }
            // 文件内容
            FILE *fp = fopen(time_filename, "wb");
            if (!fp) {
                printf("无法打开文件: %s\n", time_filename);
                break;
            }
            int received = 0;
            while (received < file_size) {
                int to_read = (file_size - received) > sizeof(buf) ? sizeof(buf) : (file_size - received);
                n = recv(client_fd, buf, to_read, 0);
                if (n <= 0) {
                    printf("文件内容接收中断\n");
                    break;
                }
                fwrite(buf, 1, n, fp);
                received += n;
                printf("已接收: %d/%d字节\r", received, file_size);
                fflush(stdout);
            }
            fsync(fileno(fp)); // 立马同步文件
            fclose(fp);
            printf("\n文件保存成功: %s\n", time_filename);
        }
        close(client_fd);
        printf("连接关闭\n");
    }
    close(server_fd);
    return 0;
}